﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace reactiveBT.Coroutines
{
    /// <summary>
    /// 协程的yield return值被允许有三种状态
    /// float代表要等待的绝对时间
    /// Ienumerator代表要等待的子协程
    /// 其他仅代表等待一帧
    /// </summary>
    public enum CoroutineState
    {
        Running,
        Suspended,
        Ready,
        Dead
    }
    public class Coroutine
    {
        public IEnumerator co;
        public System.Action fn;
        public CoroutineState state;
        public int id;
        public float delay;


        public Coroutine(IEnumerator enumerator,float delayTime)
        {
            co = enumerator;
            fn = null;
            //TODO 统一的Id生成
            id = 0;
            delay = delayTime;
            state = CoroutineState.Ready;
        }
        public Coroutine(System.Action fn,float delayTime)
        {
            this.fn = fn;
            co = null;
            //TODO 统一的Id生成
            id = 0;
            delay = delayTime;
            state = CoroutineState.Ready;
        }
        /// <summary>
        /// 这里的调用可能需要考虑到函数所属类已经被析构的问题
        /// </summary>
        /// <returns>false if coroutine is finish,or true</returns>
        public bool MoveNext(float deltaTime)
        {
            delay = delay < deltaTime ? 0 : delay - deltaTime;
            if (delay > 0)
            {
                return true;
            }
            if (co != null)
            {
                return _MoveNext(co);
            }
            else if(fn != null)
            {
                fn();
                return false;
            }
            throw new Exception("协程内函数或者迭代器为空");
        }
        private bool _MoveNext(IEnumerator coroutine)
        {
            if (coroutine.Current is IEnumerator)
            {
                if(_MoveNext(coroutine.Current as IEnumerator))
                {
                    return true;
                }
            }
            bool result = coroutine.MoveNext();
            if (coroutine.Current is float)
            {
                delay = (float)coroutine.Current;
            }
            return result;
        }
    }
}
